#!/usr/bin/env python
# -*- coding: UTF-8 -*-
##
##    Copyright (C) 2005 manatlan manatlan[at]gmail(dot)com
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published
## by the Free Software Foundation; version 2 only.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##

import os,sys
import time
import datetime
import base64,md5

from fricorder import FConfig
from fricorder import fbx
from fricorder import common
from fricorder import progtv
from fricorder import dict4ini
from fricorder import web
from fricorder.template import Template
from fricorder import api

urls = (
    '/', 'index',
    '/style.css', 'style',
    '/save', 'index',    #post
    '/action/(\w+)', 'doAction',  # get or post
    '/ajax/(\w+)', 'ajax',
)

# dict4ini global object
CFG=dict4ini.DictIni(FConfig.CONFIGFILE)

def encrypt(m):
    return base64.b64encode(md5.new(m).digest())


class Ajax:
    """
    class Ajax, indépendante de pager ...

    on créé un objet Ajax()
    on registre les méthodes d'un site/objet pager à l'aide de Ajax().register_x(<nom>)
    on register un handler pour le site/objet pager Ajax().register_handler_for( <instance> )
    et on recupere le javascript de l'ajax qu'on clak dans le html par str( Ajax() )
    comme ceci :
            js =Ajax()
            js.register_x("multiply")
            js.register_x("test")
            js.register_handler_for(self)
            code = str(js)


    l'idée c'est qu'on créé des méthodes, comme on créé des pages, dans l'objet site/pager
    on les registre dans l'ajax, de manière à ce qu'il construise les wrapper javascript
    et dans le html, on appel ces wrapper javascript x_<nom_method>([arg[,args[,args]]], <fct>)
    <fct> étant la fonction (callback) de reecriture du retour de l'appel, de la form
    "void fct(string ret)" (en js) ces wrappers en fait, appel par l'ajax(xmlhttprequest),
    et appel une page (nom_method) avec les params [arg[,args[,args]]] qui retourne du html,
    qu'on a plus qu'à claquer dans notre html initiale via <fct>
    """
    def __init__(self):
        self.__callback = []

    def register_x(self,f):
        if f not in self.__callback:
            self.__callback.append(f)

    def register_handler_for(self,obj):
        """ add an handler on 'obj' """
        def x_handler(obj,rsargs,rsrnd,rs):    # must mimic method site objet of pager

            #~ # Bust cache in the head
            #~ yield "Expires: Mon, 26 Jul 1997 05:00:00 GMT"
            #~ yield "Last-Modified: %s GMT" % datetime.datetime.utcnow().strftime(
                                                              #~ "%a, %d %m %H:%M:%S")
            #~ # always modified
            #~ yield "Cache-Control: no-cache, must-revalidate" # HTTP/1.1
            #~ yield "Pragma: no-cache"                         # HTTP/1.0
            #~ yield ""

            if hasattr(obj,rs):
                callback = getattr(obj,rs)
                yield "+:"+ str(callback(*(rsargs) ))
            else:
                yield "-:bad"

        # rajoute la methode ci-dessous a la classe du site
        obj.__class__._handler_ = x_handler

    def __repr__(self):
        return str(self)

    def __str__(self):
        js= """\
        // remote scripting library
		// (c) copyright 2005 modernmethod, inc
        //http://www.modernmethod.com/sajax/
		var sajax_debug_mode = false;

		function sajax_debug(text) {
			if (sajax_debug_mode)
				alert("RSD: " + text)
		}

 		function sajax_init_object() {
 			sajax_debug("sajax_init_object() called..")

 			var A;
			try {
				A=new ActiveXObject("Msxml2.XMLHTTP");
			} catch (e) {
				try {
					A=new ActiveXObject("Microsoft.XMLHTTP");
				} catch (oc) {
					A=null;
				}
			}
			if(!A && typeof XMLHttpRequest != "undefined")
				A = new XMLHttpRequest();
			if (!A)
				sajax_debug("Could not create connection object.");
			return A;
		}
		function sajax_do_call(func_name, url, args) {
			var i, x, n;
			url = url + "?rsrnd=" + new Date().getTime();
			for (i = 0; i < args.length-1; i++)
				url = url + "&rsargs=" + escape(args[i]);
			x = sajax_init_object();
			x.open("GET", url, true);
			x.onreadystatechange = function() {
				if (x.readyState != 4)
					return;
				sajax_debug("received " + x.responseText);

				var status;
				var data;
				status = x.responseText.charAt(0);
				data = x.responseText.substring(2);
				if (status == "-")
					alert("Error: " + data);
				else
					document.getElementById(args[args.length-1]).innerHTML=data;	// this is the function
			}
			x.send(null);
			sajax_debug(func_name + " url = " + url);
			sajax_debug(func_name + " waiting..");
			delete x;
		}
   """

        for i in self.__callback:
            js+="""
                function x_%s() {
                    sajax_do_call("%s",
                        "ajax/%s",
                        x_%s.arguments);
                } """ % (i,i,i,i)

        return js


def secure():
    global CFG
    if CFG.web.password:
        try:
            mdp=web.cookies("password").password
        except:
            mdp=None

        if mdp!=CFG.web.password:
            web.redirect("/action/authent")
    else:
        web.redirect("/action/ident")


class style:
    def GET(self):
        print open( os.path.join(FConfig.DATADIR,"templates","style.css") ,"r").read()


class index:
    def GET(self):
        #=====================================
        secure()
        #=====================================

        date = datetime.datetime.now()
        web.header("Content-type","text/html")

        js =Ajax()
        js.register_x("refresh")
        script = str(js)

        chaines = fbx.getStreams()
        jours=[(i,common.affDate(jour)) for i,jour in api.getJours(date,14)]
        qualites=[(api.getQualite().index(i),i) for i in api.getQualite()]
        destination = CFG.config.destination or ""
        qualite=CFG.config.qualite or 0
        liste=[]
        for code,chaine,deb,duree in api.getAtList():
            adate = common.affDate(deb)
            heure = deb.strftime("%H:%M")
            fin = (deb+datetime.timedelta(minutes=duree)).strftime("%H:%M")
            fileId = api.FileId.make(chaine,deb,duree)

            file=api.FileId.genPidFileName(fileId)
            if os.path.isfile(file):
                color="red"
            else:
                color="white"

            isHalt=api.FileId.isHaltFileName(fileId)

            liste.append( (code,chaine,adate,heure,fin,fileId,color,isHalt) )
        fuckCache=date.strftime("%H%M%S")

        print Template("index.html")

    def POST(self):
        #=====================================
        secure()
        #=====================================

        date = datetime.datetime.now()  #bug possible a 0h00 !!!
        data=web.input()
        msg=None

        # determine chaine, url
        if data.chaine:
            chaine=None
            url=None
            for num,c,u in fbx.getStreams():
                if num == int(data.chaine or 0):
                    chaine = common.normalize(c) #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                    url = u
                    break

            #determine le jour
            jour=api.getJours(date,14)[int(data.jour)][1]

            #determine l'heure
            debut=None
            if data.heure:
                if ":" in data.heure: t = data.heure.split(":")
                if "-" in data.heure: t = data.heure.split("-")
                if "," in data.heure: t = data.heure.split(",")
                if " " in data.heure: t = data.heure.split(" ")
                if "." in data.heure: t = data.heure.split(".")
                if len(t)>0:
                    h,m=int(t[0]),int(t[1])
                    if h in range(24) and m in range(60):
                        debut=datetime.datetime(jour.year,jour.month,jour.day,h,m)
            if debut:
                #determine le reste
                duree=int(data.duree or 0)
                qualite=api.getQualite()[int(data.qualite)]
                destination=data.destination.strip()

                if duree>0:
                    if os.path.isdir(data.destination):
                        #~ print chaine,"<hr>"
                        #~ print url,"<hr>"
                        #~ print debut,"<hr>"
                        #~ print duree,"<hr>"
                        #~ print qualite,"<hr>"
                        #~ print destination,"<hr>"
                        #~ return
                        CFG.config.qualite = int(data.qualite)
                        CFG.config.destination =data.destination.strip()
                        CFG.save()
                        msg=api.runAt(url,chaine,qualite,debut,duree,destination)
                    else:
                        msg = "Votre répertoire de destination n'existe pas"
                else:
                    msg = "La durée de l'enregistrement n'est pas bonne"
            else:
                msg = "Votre heure de debut n'est pas bonne"
        else:
            msg = "Vous n'avez pas selectionner de chaine"


        if not msg:
            web.redirect("/")
        else:
            web.header("Content-type","text/html")
            print Template("message.html")

class doAction:
    def GET(self,action):
        if action=="supprime":
            #=====================================
            secure()
            #=====================================
            data=web.input()
            api.cancelJob(int(data.job),data.fileid)
            web.redirect("/")
        elif action=="toggle":
            #=====================================
            secure()
            #=====================================
            data=web.input()
            api.FileId.toggleHaltFileName(data.fileid)
            web.redirect("/")
        elif action=="authent":
            # l'utilisateur est connu : faut son password
            print Template("authent.html")
        elif action=="ident":
            # l'utilisateur n'est pas connu
            print Template("authent.html")

    def POST(self,action):
        data = web.input()
        if action == "authent":
            if encrypt(data.password1) == CFG.web.password:
                web.setcookie("password", CFG.web.password)
        elif action == "ident":
            if data.password1==data.password2:
                CFG.web.password = encrypt(data.password1)
                CFG.save()
                web.setcookie("password", CFG.web.password)
        web.redirect("/")


class ajax:
    def GET(self,action):
        if action=="refresh":
            print " "
            data=web.input()

            chaine=None
            if data.rsargs[0].value:
                url=None
                for num,c,u in fbx.getStreams():
                    if num == int(data.rsargs[0].value or 0):
                        chaine = c

            date = datetime.datetime.now()  #bug possible a 0h00 !!!
            jour=api.getJours(date,14)[int(data.rsargs[1].value)][1]
            if chaine and jour:
                chaineTV = fbx.convChaine(chaine)
                progs = progtv.getProgs(chaineTV.decode("utf_8"),jour)

                if progs:
                    liste=[]
                    for dt,duree,titre in progs:
                        liste.append([dt.strftime("%H:%M"),titre.encode("utf_8"), duree])
                    print Template("tvlist.html")





def main():
    if CFG.config.xmltv and os.path.isfile(CFG.config.xmltv):
        progtv.init(CFG.config.xmltv)


    if api.isAtdRunning():
        try:
            web.internalerror = web.debugerror
            web.run(urls)
        except KeyboardInterrupt:
            print "bye"
        #~ web.run(urls)
    else:
        print "Le démon ATD ne semble pas tourner sur votre ordinateur, par conséquent fricorder ne sera pas utilisable."


if __name__ == "__main__":
    main()
